// Copyright (C) Microsoft Corporation. All rights reserved.

using System;
using System.Text;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.Net;
using System.Web.Services.Protocols;
using Microsoft.DDSolutions.SharePoint;
using Microsoft.DDSolutions.SqlReportServer;
using Microsoft.DDSolutions.Tfs;
using Microsoft.TeamFoundation.Client;
using Microsoft.VisualStudio.TestTools.UnitTesting;

namespace Microsoft.DDSolutions.TfsAdmin.Tests
{
    /// <summary>
    /// This class contains unit TestMethods for the SPServerProxy class.
    /// </summary>
    /// <remarks>
    /// For any of the TestMethod methods where we do more than get consistent information,
    /// we need to ensure that multiple users running the TestMethods simultaneously doesn't
    /// break the TestMethods.
    /// </remarks>
    [TestClass]
    public class SharePointUnitTestMethods : IDisposable
    {
        SPServerProxy spProxy;
        bool disposed;
        TestConfig tc;

        /// <summary>
        /// Creates the SPServerProxy object. Load TestMethod config from TestMethodConfig.xml file which has the TFS server name, Team project name,
        /// TestMethod domain usernames.
        /// </summary>
        [TestInitialize]
        public void Init()
        {
            tc = TestConfig.Load("TestConfig.xml");
            TeamFoundationServer tfsAppServer = new TeamFoundationServer(tc.Server);
            Microsoft.DDSolutions.Tfs.TfsServerProxy tfs = new Microsoft.DDSolutions.Tfs.TfsServerProxy();
            tfs.Connect(tfsAppServer);
            spProxy = new SPServerProxy(tfs.BaseSiteUrl.ToString(), tfs.AdminServiceUrl.ToString());
            spProxy.IsProjectSite = true;

            /// Make sure all the Share Point Roles assigned for users in the config file actually
            /// exist on the sharepoint server.
            foreach (DomainUser user in tc.DomainUsers)
            {
                /// Make sure the user has atleast one SharePoint Role assigned.
                Assert.IsTrue(user.SPRoles.Length > 0, TestResource.strMissingRole);

                foreach(string spRole in user.SPRoles)
                Assert.IsTrue(spProxy.IsRoleExist(spRole, tc.TeamProject), TestResource.strMissingRole);
            }


            /// Add the users in the config file to the TFS SharePoint site.
            SharePointAddUsers();
        }

        /// <summary>
        ///   Cleanup. Remove all users added during Setup above.
        /// </summary>
        [TestCleanup]
        public void TeardownFixture()
        {
            SharePointRemoveUsers();
        }

        /// <summary>
        ///  Dispose method to dispose the Web Service resource.
        /// </summary>
        public void Dispose()
        {
            Dispose(true);
            GC.SuppressFinalize(this);
        }

        protected virtual void Dispose(bool disposing)
        {
            if (disposed == true) return;

            if (disposing)
            {
                spProxy.Dispose();
                disposed = true;
            }
        }

        #region Additional TestMethod attributes
        //
        // You can use the following additional attributes as you write your TestMethods:
        //
        // Use ClassInitialize to run code before running the first TestMethod in the class
        // [ClassInitialize()]
        // public static void MyClassInitialize(TestMethodContext TestMethodContext) { }
        //
        // Use ClassCleanup to run code after all TestMethods in a class have run
        // [ClassCleanup()]
        // public static void MyClassCleanup() { }
        //
        // Use TestMethodInitialize to run code before running each TestMethod 
        // [TestMethodInitialize()]
        // public void MyTestMethodInitialize() { }
        //
        // Use TestMethodCleanup to run code after each TestMethod has run
        // [TestMethodCleanup()]
        // public void MyTestMethodCleanup() { }
        //
        #endregion

        /// <summary>
        /// Ensures that GetRoles returns the expected list of roles.
        /// </summary>
        [TestMethod]
        public void SharePointGetRoles()
        {
            ReadOnlyCollection<string> actual = spProxy.GetRoles(tc.TeamProject);

            foreach (DomainUser user in tc.DomainUsers)
            {
                foreach (string spRole in user.SPRoles)
                {
                    CollectionAssert.Contains(actual, spRole, spRole + TestResource.MissingRoleMsg);
                }
            }
         
        }

        /// <summary>
        /// TestMethods GetRoles's behavior when passing it a null sitename.
        /// </summary>
        [TestMethod]
        public void SharePointGetRolesNullSite()
        {
            bool caughtException = false;

            try
            {
                spProxy.GetRoles(null);
            }
            catch (Microsoft.DDSolutions.SharePoint.InvalidSPServerException)
            {
                caughtException = true;
            }

            Assert.IsTrue(caughtException, TestResource.SpGetRolesNoWebExecpMsg);
        }

        /// <summary>
        /// TestMethods GetRoleCollectionFromUser's behavior when passing it a null username.
        /// </summary>
        [TestMethod]
        public void SharePointGetRolesForUserNullParameter()
        {
            bool caughtException = false;

            try
            {
                spProxy.GetRoleCollectionFromUser(null, tc.TeamProject);
            }
            catch (Microsoft.DDSolutions.SharePoint.InvalidSPUserException)
            {
                caughtException = true;
            }

            Assert.IsTrue(caughtException, TestResource.SpNoInvalidUserExecpMsg);
        }

        /// <summary>
        /// TestMethods adding a users to the sharepoint site. This is invoked as part of Setup.
        /// </summary>
       
        public void SharePointAddUsers()
        {
            foreach (DomainUser user in tc.DomainUsers)
            {
                string domainUserName = tc.GetDomainUserName(user.UserName);

                foreach (string spRole in user.SPRoles)
                    spProxy.AddUser(domainUserName, tc.TeamProject, spRole, string.Empty, string.Empty, string.Empty);

            }
        }

        /// <summary>
        /// Removing users from the sharepoint site. This is invoked as part of TearDownFixture
        /// </summary>

        public void SharePointRemoveUsers()
        {
            foreach (DomainUser user in tc.DomainUsers)
            {
                string domainUserName = tc.GetDomainUserName(user.UserName);
                spProxy.RemoveUser(domainUserName, tc.TeamProject);
            }
        }

        /// <summary>
        /// Ensures that GetRoleCollectionFromUser returns the correct roles for particular users.
        /// </summary>
        [TestMethod]
        public void SharePointGetRolesForUser()
        {
            ReadOnlyCollection<string> roles;

            foreach (DomainUser user in tc.DomainUsers)
            {
                roles = spProxy.GetRoleCollectionFromUser(tc.GetDomainUserName(user.UserName), tc.TeamProject);
                
                foreach(string spRole in user.SPRoles)
                    CollectionAssert.Contains(roles, spRole, user.UserName + TestResource.strMissingRole + spRole);
            }
        }

        
        /// <summary>
        /// Ensures that IsRoleExist returns true for roles that exist and returns false for fake roles.
        /// </summary>
        [TestMethod]
        public void SharePointIsRoleExist()
        {
            // Confirm a 'bad role' doesn't exist.
            Assert.IsFalse(spProxy.IsRoleExist("Bad Role", tc.TeamProject), TestResource.SpInvalidRoleExistMsg);
        }

        /// <summary>
        /// TestMethods IsRoleExist's behavior when passing it null parameters.
        /// </summary>
        [TestMethod]
        public void SharePointIsRoleExistNullParameter()
        {
            bool caughtException = false;

            try
            {
                spProxy.IsRoleExist(null, null);
            }
            catch (Microsoft.DDSolutions.SharePoint.InvalidSPServerException)
            {
                caughtException = true;
            }


            Assert.IsTrue(caughtException, TestResource.SpNoInvalidSpServerExecpMsg);
            Assert.IsFalse(spProxy.IsRoleExist(null, tc.TeamProject), TestResource.SpIsRoleExistReturnsTrueForNullUserMsg);
        }

       
        /// <summary>
        /// TestMethods AddUser's behavior when adding a non-existent account.
        /// </summary>
        [TestMethod]
        public void SharePointAddUserFakePerson()
        {
            bool caughtException = false;
            string spRole = tc.DomainUsers[0].SPRoles[0];
            string userName = TestResource.strUserBillyBob;

            try
            {
                spProxy.AddUser(userName,tc.TeamProject,spRole,"Billy Bob", "billybob@nonexist.com", "A billy user." );
            }
            catch (SoapException)
            {
                caughtException = true;      
            }

            // If no exception was thrown, remove the user before failing the assert.
            if (!caughtException)
            {
                spProxy.RemoveUserFromRole(userName, tc.TeamProject, TestResource.strReader);
            }

            Assert.IsTrue(caughtException, userName + TestResource.SpAddUserNoSoapExecpMsg);
        }

       
        /// <summary>
        /// TestMethods RemoveUser's behavior when attempting to remove a user that wasn't added.
        /// </summary>
        [TestMethod]
        public void SharePointRemoveUserFailure()
        {
            bool caughtException = false;

            try
            {
                spProxy.RemoveUserFromRole(TestResource.strUserInvalid, tc.TeamProject, TestResource.strSpAdministrator);
            }
            catch (SoapException)
            {
                caughtException = true;
            }

            Assert.IsTrue(caughtException, TestResource.SpRemoveInvalidUserMsg);
        }

    }
}
